/* A wee progam to test the spangling sockets. */

/* #define _P __P */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#define SEND_SIZE 4096 // 8192 /*16384*/
#define POLL_COUNT 1
#include "mptcpMgr.h"
#include <time.h>
#define MAX_CONNS 300
#define SOCKBUF 400000 //(64*1024)
#ifdef NO_THREADS
extern void *my_upcall_worker(void *arg); 
#endif
int my_port; 
void *single_sender(int fd);
int send_size_list[] = {14000, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384}; 

/*
 * Variables shared between all threads.
 */

int touch_data;
int             num_to_send;
struct hostent *he;
char *hname; //the name and address of the remote host
unsigned int haddr;
int             port;
int             frames_sent = 0;
struct timeval  main_timer;

long tvdif2us(struct timeval *t0, struct timeval *t1)
{
  struct timeval tdiff;
  long us;

  tdiff.tv_sec = t1->tv_sec - t0->tv_sec;
  tdiff.tv_usec = t1->tv_usec - t0->tv_usec;
  if (tdiff.tv_usec < 0)
    tdiff.tv_sec--, tdiff.tv_usec += 1000000;

  us = ((long)tdiff.tv_sec*1000000) + tdiff.tv_usec;
  return us;
}

int main(int argc, char *argv[])
{
#ifdef USER_STACK
    pthread_t threads[MAX_CONNS];
#endif
    int       i;
    int ii; 
    int nd,fd; 
    int rr, ss; 

    if (argc < 4)
    {
      fprintf(stderr, 
	      "%s: Usage: %s <host> <port> <my-port> [<interface_list>]\n", argv[0], argv[0]); 
      exit(EXIT_FAILURE);
    }

    /*
     * Initialise the stack as early as possible. It does some gross memory
     * mapping that is necessary for us not to crash!
     */

    //allocate memory for he
    if ((he = (struct hostent *)malloc(sizeof(struct hostent))) == NULL){
	printf("Couldn't allocate memory for host name.\n");
	exit(2);
    }

    /*
     * Parse the command line.
     */

    my_port = atoi(argv[3]); 

    port = strtol(argv[2], NULL, 10);
    if(errno == ERANGE || port > 65535 || port < 0)
    {
	fprintf(stderr, "%s: port \"%s\" invalid.\n", argv[0], argv[2]);
	exit(EXIT_FAILURE);
    }


    *he=*((struct hostent*) gethostbyname(argv[1]));

    if(he == NULL)
      {
	fprintf(stderr, "%s: failed to look up host \"%s\", reason: ", 
		argv[0], argv[11+rr*2]);
	herror(NULL);
	fprintf(stderr, "\n");
	exit(EXIT_FAILURE);	
      }
    
    if(he->h_addrtype != AF_INET || he->h_length != 4)
      {
	fprintf(stderr, "%s: host \"%s\" has non-IPv4 address.\n", 
		argv[0], argv[1]);
	exit(EXIT_FAILURE);
      }
    
    //store the name and address
    haddr = *((unsigned int*)he->h_addr);
    hname = (char *) malloc(sizeof(char) * strlen(he->h_name)+1);
    memcpy(hname, he->h_name, strlen(he->h_name)+1);
    
    fd = mptcp_socket(AF_INET, SOCK_STREAM, 0, my_port);

    if ( fd < 0 ){
      fprintf(stderr, "Socket failed: %d (%s)\n",errno, strerror(errno));
      return(1);
    }

    //bind here if necessary
    struct sockaddr_in addr;
    mptcp_bind(fd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in), argv, argc, 4);
    
    single_sender(fd); 

    /* Kill off the stack, and finish. */

    printf("Killing stack...\n");
    user_kill();
    printf("Stack dead!\n");

    exit(EXIT_SUCCESS);
}
    

void *single_sender(int fd)
{

  // single sender for multiple tcp connections, without opening any threads... 

    //Removed references to the volatile struct hostent *he pointer -S

    int                old_bufs_to_send, bufs_to_send;
    struct timeval     old_time, curr_time, start_time;
    struct sockaddr_in raddr;
    unsigned char      *buf;
    int                i;
    int                ret;
    int part_send;
    int total_send = 0; 
    int count=0; 
    float min_delay = 100000; 
    float max_delay = 0; 
    float avg_delay = 0; 
    int num_stats = 0; 
    float cur_delay = 0; 

    int newbuf1, newbuf2;
    socklen_t len1 = sizeof(int); 
    int newbuf = SOCKBUF;
    int bytes_to_send; 
    int poll; 
    fd_set readfds;
    fd_set writefds; 
    struct timeval tv1; 
    int MAXFD=0; 
    int RMAXFD = 0; 
    int ready; 
    
    /* Set up the remote address. */

    bytes_to_send = send_size_list[0]; 

    buf = (unsigned char *) malloc(sizeof(unsigned char)*bytes_to_send); 

    /* Fill in some realistic data ;-) */
    for ( i = 0; i < bytes_to_send; i++ ) 
      buf[i] = '-';

    /* Create an exciting new user-space TCP connection! */

    printf("Sending to %s:%d.\n", hname, port);

    raddr.sin_addr.s_addr = haddr;
    raddr.sin_port        = htons(port);
    raddr.sin_family      = AF_INET;
    
    my_upcall_worker(NULL); 
    printf("Connecting...to host %s:%d\n", hname, port); fflush(stdout); 

    if ( (ret = mptcp_connect(fd, (struct sockaddr *)&raddr, 
			     sizeof(struct sockaddr_in))) < 0 ){
      if (errno != EINPROGRESS)	  {
	fprintf(stderr, "connect failed: %d (%s)\n",errno, strerror(errno));
	return((void*)1);
      }
      else  {
	printf("\nno threads... errno=%d (%s) ", errno, strerror(errno)); 
	fflush(stdout); 
      }
    }
    printf("\nConnected (ret=%d) to \t%s\n", ret, hname);
    
    old_bufs_to_send = bufs_to_send = num_to_send;
    
    if (mptcp_getsockopt(fd, SOL_SOCKET, SO_RCVBUF,(int *) &newbuf1, &len1) || 
	mptcp_getsockopt(fd, SOL_SOCKET, SO_SNDBUF,(int *) &newbuf2, &len1)){
      printf("FIGHT in getsockopt\n"); 
      exit(2); 
    }
    printf("\nrecv_buf is %d and send buf is %d\n", newbuf1, newbuf2); 
    
    // doing set/get _after_ connect -P2
    
    // loop:
    FD_ZERO(&writefds); 
    ready = 0; 

    part_send = 0;
    while(1){
      my_upcall_worker(NULL); 

      FD_SET(fd, &writefds); 
      if (fd > MAXFD)
	MAXFD = fd; 
      
      tv1.tv_sec = 0; 
      tv1.tv_usec = 0; 
      
      mptcp_select(MAXFD+1, NULL, &writefds, NULL, &tv1); 
	
      if (FD_ISSET(fd, &writefds)){
	if (ready==0){
	  if (mptcp_getsockopt(fd, SOL_SOCKET, SO_RCVBUF,(int *) &newbuf1, &len1) || 
	      mptcp_getsockopt(fd, SOL_SOCKET, SO_SNDBUF,(int *) &newbuf2, &len1)){
	    printf("FIGHT in getsockopt\n"); 
	    exit(2); 
	  }
	  printf("\nrecv_buf is %d and send buf is %d\n", newbuf1, newbuf2); 
	  ready = 1;
	}
	if (part_send >= bytes_to_send)
	  part_send = 0;
	do { 
	  int j;
	  ret = mptcp_send(fd, buf, sizeof(buf) , MSG_DONTWAIT);
	  if ( ret < 0 ){
	    if (errno == EWOULDBLOCK){
	      //printf("Got EWOULDBLOCK after transferring %d bytes...", ret); 
	      //fflush(stdout); 
	      break; 
	    }
	    fprintf(stderr, "send failed: %d (%s)\n",
		     errno, strerror(errno));
	    return((void*)1);
	  }
	  else {
	    // printf("\nsent %d bytes\n",ret); 
	    // fflush(stdout); 
	  }

	} while (1);
      }
    }
 // if FD_ISSET(fd, 
 
    
    my_upcall_worker(NULL); 
    
    if ((ret = mptcp_shutdown(fd, 2)) < 0){
      fprintf(stderr, "\nshutdown failed: %d (%s)\n",
	      errno, strerror(errno));
      return((void*)1);
    }
    
    ret = mptcp_close(fd);
    if ( ret < 0 )	{
      fprintf(stderr, "close failed: %d (%s)\n",errno, strerror(errno));
      return((void*)1);
    }		
} 

/* End of $RCSFile$ */

